{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "922d3343",
   "metadata": {},
   "source": [
    "# Built-In Observability Instrumentation\n",
    "\n",
    "Within LlamaIndex, many events and spans are created and logged through our instrumentation system.\n",
    "\n",
    "This notebook walks through how you would hook into these events and spans to create your own observability tooling."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38f1cb3a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install llama-index treelib"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae30a3b7",
   "metadata": {},
   "source": [
    "## Events\n",
    "\n",
    "LlamaIndex logs several types of events. Events are singular data points that occur during runtime, and usually belong to some parent span.\n",
    "\n",
    "Below is a thorough list of what is logged, and how to create an event handler to read these events."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ed1c35a-ad39-477c-8a13-58a672ebbb57",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Dict, List\n",
    "from treelib import Tree\n",
    "\n",
    "from llama_index.core.instrumentation.events import BaseEvent\n",
    "from llama_index.core.instrumentation.event_handlers import BaseEventHandler\n",
    "\n",
    "from llama_index.core.instrumentation.events.agent import (\n",
    "    AgentChatWithStepStartEvent,\n",
    "    AgentChatWithStepEndEvent,\n",
    "    AgentRunStepStartEvent,\n",
    "    AgentRunStepEndEvent,\n",
    "    AgentToolCallEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.chat_engine import (\n",
    "    StreamChatErrorEvent,\n",
    "    StreamChatDeltaReceivedEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.embedding import (\n",
    "    EmbeddingStartEvent,\n",
    "    EmbeddingEndEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.llm import (\n",
    "    LLMPredictEndEvent,\n",
    "    LLMPredictStartEvent,\n",
    "    LLMStructuredPredictEndEvent,\n",
    "    LLMStructuredPredictStartEvent,\n",
    "    LLMCompletionEndEvent,\n",
    "    LLMCompletionStartEvent,\n",
    "    LLMChatEndEvent,\n",
    "    LLMChatStartEvent,\n",
    "    LLMChatInProgressEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.query import (\n",
    "    QueryStartEvent,\n",
    "    QueryEndEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.rerank import (\n",
    "    ReRankStartEvent,\n",
    "    ReRankEndEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.retrieval import (\n",
    "    RetrievalStartEvent,\n",
    "    RetrievalEndEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.span import (\n",
    "    SpanDropEvent,\n",
    ")\n",
    "from llama_index.core.instrumentation.events.synthesis import (\n",
    "    SynthesizeStartEvent,\n",
    "    SynthesizeEndEvent,\n",
    "    GetResponseEndEvent,\n",
    "    GetResponseStartEvent,\n",
    ")\n",
    "\n",
    "\n",
    "class ExampleEventHandler(BaseEventHandler):\n",
    "    \"\"\"Example event handler.\n",
    "\n",
    "    This event handler is an example of how to create a custom event handler.\n",
    "\n",
    "    In general, logged events are treated as single events in a point in time,\n",
    "    that link to a span. The span is a collection of events that are related to\n",
    "    a single task. The span is identified by a unique span_id.\n",
    "\n",
    "    While events are independent, there is some hierarchy.\n",
    "    For example, in query_engine.query() call with a reranker attached:\n",
    "    - QueryStartEvent\n",
    "    - RetrievalStartEvent\n",
    "    - EmbeddingStartEvent\n",
    "    - EmbeddingEndEvent\n",
    "    - RetrievalEndEvent\n",
    "    - RerankStartEvent\n",
    "    - RerankEndEvent\n",
    "    - SynthesizeStartEvent\n",
    "    - GetResponseStartEvent\n",
    "    - LLMPredictStartEvent\n",
    "    - LLMChatStartEvent\n",
    "    - LLMChatEndEvent\n",
    "    - LLMPredictEndEvent\n",
    "    - GetResponseEndEvent\n",
    "    - SynthesizeEndEvent\n",
    "    - QueryEndEvent\n",
    "    \"\"\"\n",
    "\n",
    "    events: List[BaseEvent] = []\n",
    "\n",
    "    @classmethod\n",
    "    def class_name(cls) -> str:\n",
    "        \"\"\"Class name.\"\"\"\n",
    "        return \"ExampleEventHandler\"\n",
    "\n",
    "    def handle(self, event: BaseEvent) -> None:\n",
    "        \"\"\"Logic for handling event.\"\"\"\n",
    "        print(\"-----------------------\")\n",
    "        # all events have these attributes\n",
    "        print(event.id_)\n",
    "        print(event.timestamp)\n",
    "        print(event.span_id)\n",
    "\n",
    "        # event specific attributes\n",
    "        print(f\"Event type: {event.class_name()}\")\n",
    "        if isinstance(event, AgentRunStepStartEvent):\n",
    "            print(event.task_id)\n",
    "            print(event.step)\n",
    "            print(event.input)\n",
    "        if isinstance(event, AgentRunStepEndEvent):\n",
    "            print(event.step_output)\n",
    "        if isinstance(event, AgentChatWithStepStartEvent):\n",
    "            print(event.user_msg)\n",
    "        if isinstance(event, AgentChatWithStepEndEvent):\n",
    "            print(event.response)\n",
    "        if isinstance(event, AgentToolCallEvent):\n",
    "            print(event.arguments)\n",
    "            print(event.tool.name)\n",
    "            print(event.tool.description)\n",
    "            print(event.tool.to_openai_tool())\n",
    "        if isinstance(event, StreamChatDeltaReceivedEvent):\n",
    "            print(event.delta)\n",
    "        if isinstance(event, StreamChatErrorEvent):\n",
    "            print(event.exception)\n",
    "        if isinstance(event, EmbeddingStartEvent):\n",
    "            print(event.model_dict)\n",
    "        if isinstance(event, EmbeddingEndEvent):\n",
    "            print(event.chunks)\n",
    "            print(event.embeddings[0][:5])  # avoid printing all embeddings\n",
    "        if isinstance(event, LLMPredictStartEvent):\n",
    "            print(event.template)\n",
    "            print(event.template_args)\n",
    "        if isinstance(event, LLMPredictEndEvent):\n",
    "            print(event.output)\n",
    "        if isinstance(event, LLMStructuredPredictStartEvent):\n",
    "            print(event.template)\n",
    "            print(event.template_args)\n",
    "            print(event.output_cls)\n",
    "        if isinstance(event, LLMStructuredPredictEndEvent):\n",
    "            print(event.output)\n",
    "        if isinstance(event, LLMCompletionStartEvent):\n",
    "            print(event.model_dict)\n",
    "            print(event.prompt)\n",
    "            print(event.additional_kwargs)\n",
    "        if isinstance(event, LLMCompletionEndEvent):\n",
    "            print(event.response)\n",
    "            print(event.prompt)\n",
    "        if isinstance(event, LLMChatInProgressEvent):\n",
    "            print(event.messages)\n",
    "            print(event.response)\n",
    "        if isinstance(event, LLMChatStartEvent):\n",
    "            print(event.messages)\n",
    "            print(event.additional_kwargs)\n",
    "            print(event.model_dict)\n",
    "        if isinstance(event, LLMChatEndEvent):\n",
    "            print(event.messages)\n",
    "            print(event.response)\n",
    "        if isinstance(event, RetrievalStartEvent):\n",
    "            print(event.str_or_query_bundle)\n",
    "        if isinstance(event, RetrievalEndEvent):\n",
    "            print(event.str_or_query_bundle)\n",
    "            print(event.nodes)\n",
    "        if isinstance(event, ReRankStartEvent):\n",
    "            print(event.query)\n",
    "            print(event.nodes)\n",
    "            print(event.top_n)\n",
    "            print(event.model_name)\n",
    "        if isinstance(event, ReRankEndEvent):\n",
    "            print(event.nodes)\n",
    "        if isinstance(event, QueryStartEvent):\n",
    "            print(event.query)\n",
    "        if isinstance(event, QueryEndEvent):\n",
    "            print(event.response)\n",
    "            print(event.query)\n",
    "        if isinstance(event, SpanDropEvent):\n",
    "            print(event.err_str)\n",
    "        if isinstance(event, SynthesizeStartEvent):\n",
    "            print(event.query)\n",
    "        if isinstance(event, SynthesizeEndEvent):\n",
    "            print(event.response)\n",
    "            print(event.query)\n",
    "        if isinstance(event, GetResponseStartEvent):\n",
    "            print(event.query_str)\n",
    "\n",
    "        self.events.append(event)\n",
    "        print(\"-----------------------\")\n",
    "\n",
    "    def _get_events_by_span(self) -> Dict[str, List[BaseEvent]]:\n",
    "        events_by_span: Dict[str, List[BaseEvent]] = {}\n",
    "        for event in self.events:\n",
    "            if event.span_id in events_by_span:\n",
    "                events_by_span[event.span_id].append(event)\n",
    "            else:\n",
    "                events_by_span[event.span_id] = [event]\n",
    "        return events_by_span\n",
    "\n",
    "    def _get_event_span_trees(self) -> List[Tree]:\n",
    "        events_by_span = self._get_events_by_span()\n",
    "\n",
    "        trees = []\n",
    "        tree = Tree()\n",
    "\n",
    "        for span, sorted_events in events_by_span.items():\n",
    "            # create root node i.e. span node\n",
    "            tree.create_node(\n",
    "                tag=f\"{span} (SPAN)\",\n",
    "                identifier=span,\n",
    "                parent=None,\n",
    "                data=sorted_events[0].timestamp,\n",
    "            )\n",
    "\n",
    "            for event in sorted_events:\n",
    "                tree.create_node(\n",
    "                    tag=f\"{event.class_name()}: {event.id_}\",\n",
    "                    identifier=event.id_,\n",
    "                    parent=event.span_id,\n",
    "                    data=event.timestamp,\n",
    "                )\n",
    "\n",
    "            trees.append(tree)\n",
    "            tree = Tree()\n",
    "        return trees\n",
    "\n",
    "    def print_event_span_trees(self) -> None:\n",
    "        \"\"\"Method for viewing trace trees.\"\"\"\n",
    "        trees = self._get_event_span_trees()\n",
    "        for tree in trees:\n",
    "            print(\n",
    "                tree.show(\n",
    "                    stdout=False, sorting=True, key=lambda node: node.data\n",
    "                )\n",
    "            )\n",
    "            print(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b69b5d49",
   "metadata": {},
   "source": [
    "## Spans\n",
    "\n",
    "Spans are \"operations\" in LlamaIndex (typically function calls). Spans can contain more spans, and each span contains associated events.\n",
    "\n",
    "The below code shows how to observe spans as they happen in LlamaIndex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "79ea10ff-9918-4279-bf6e-ef025061e448",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Any, Optional\n",
    "\n",
    "from llama_index.core.instrumentation.span import SimpleSpan\n",
    "from llama_index.core.instrumentation.span_handlers.base import BaseSpanHandler\n",
    "\n",
    "\n",
    "class ExampleSpanHandler(BaseSpanHandler[SimpleSpan]):\n",
    "    span_dict = {}\n",
    "\n",
    "    @classmethod\n",
    "    def class_name(cls) -> str:\n",
    "        \"\"\"Class name.\"\"\"\n",
    "        return \"ExampleSpanHandler\"\n",
    "\n",
    "    def new_span(\n",
    "        self,\n",
    "        id_: str,\n",
    "        bound_args: Any,\n",
    "        instance: Optional[Any] = None,\n",
    "        parent_span_id: Optional[str] = None,\n",
    "        tags: Optional[Dict[str, Any]] = None,\n",
    "        **kwargs: Any,\n",
    "    ) -> Optional[SimpleSpan]:\n",
    "        \"\"\"Create a span.\"\"\"\n",
    "        # logic for creating a new MyCustomSpan\n",
    "        if id_ not in self.span_dict:\n",
    "            self.span_dict[id_] = []\n",
    "        self.span_dict[id_].append(\n",
    "            SimpleSpan(id_=id_, parent_id=parent_span_id)\n",
    "        )\n",
    "\n",
    "    def prepare_to_exit_span(\n",
    "        self,\n",
    "        id_: str,\n",
    "        bound_args: Any,\n",
    "        instance: Optional[Any] = None,\n",
    "        result: Optional[Any] = None,\n",
    "        **kwargs: Any,\n",
    "    ) -> Any:\n",
    "        \"\"\"Logic for preparing to exit a span.\"\"\"\n",
    "        pass\n",
    "        # if id in self.span_dict:\n",
    "        #    return self.span_dict[id].pop()\n",
    "\n",
    "    def prepare_to_drop_span(\n",
    "        self,\n",
    "        id_: str,\n",
    "        bound_args: Any,\n",
    "        instance: Optional[Any] = None,\n",
    "        err: Optional[BaseException] = None,\n",
    "        **kwargs: Any,\n",
    "    ) -> Any:\n",
    "        \"\"\"Logic for preparing to drop a span.\"\"\"\n",
    "        pass\n",
    "        # if id in self.span_dict:\n",
    "        #    return self.span_dict[id].pop()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "138afae2",
   "metadata": {},
   "source": [
    "## Putting it all Together\n",
    "\n",
    "With our span handler and event handler defined, we can attach it to a dispatcher watch events and spans come in.\n",
    "\n",
    "It is not mandatory to have both a span handler and event handler, you could have either-or, or both."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49279726-a6a0-4b21-8d51-6786e8dca279",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core.instrumentation import get_dispatcher\n",
    "from llama_index.core.instrumentation.span_handlers import SimpleSpanHandler\n",
    "\n",
    "# root dispatcher\n",
    "root_dispatcher = get_dispatcher()\n",
    "\n",
    "# register span handler\n",
    "event_handler = ExampleEventHandler()\n",
    "span_handler = ExampleSpanHandler()\n",
    "simple_span_handler = SimpleSpanHandler()\n",
    "root_dispatcher.add_span_handler(span_handler)\n",
    "root_dispatcher.add_span_handler(simple_span_handler)\n",
    "root_dispatcher.add_event_handler(event_handler)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "290a001d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24a5a406-e9d2-4845-98f1-39b60a367373",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-----------------------\n",
      "7182e98f-1b8a-4aba-af18-3982b862c794\n",
      "2024-05-06 14:00:35.931813\n",
      "BaseEmbedding.get_text_embedding_batch-632972aa-3345-49cb-ae2f-46f3166e3afc\n",
      "Event type: EmbeddingStartEvent\n",
      "{'model_name': 'text-embedding-ada-002', 'embed_batch_size': 100, 'num_workers': None, 'additional_kwargs': {}, 'api_base': 'https://api.openai.com/v1', 'api_version': '', 'max_retries': 10, 'timeout': 60.0, 'default_headers': None, 'reuse_client': True, 'dimensions': None, 'class_name': 'OpenAIEmbedding'}\n",
      "-----------------------\n",
      "-----------------------\n",
      "ba86e41f-cadf-4f1f-8908-8ee90404d668\n",
      "2024-05-06 14:00:36.256237\n",
      "BaseEmbedding.get_text_embedding_batch-632972aa-3345-49cb-ae2f-46f3166e3afc\n",
      "Event type: EmbeddingEndEvent\n",
      "['filename: README.md\\ncategory: codebase\\n\\nContext\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.']\n",
      "[-0.005768016912043095, 0.02242799662053585, -0.020438531413674355, -0.040361806750297546, -0.01757599227130413]\n",
      "-----------------------\n",
      "-----------------------\n",
      "06935377-f1e4-4fb9-b866-86f7520dfe2b\n",
      "2024-05-06 14:00:36.305798\n",
      "BaseQueryEngine.query-a766ae6c-6445-43b4-b1fc-9c29bae99556\n",
      "Event type: QueryStartEvent\n",
      "Tell me about LLMs?\n",
      "-----------------------\n",
      "-----------------------\n",
      "62608f4f-67a1-4e2c-a653-24a4430529bb\n",
      "2024-05-06 14:00:36.305998\n",
      "BaseRetriever.retrieve-4e25a2a3-43a9-45e3-a7b9-59f4d54e8f00\n",
      "Event type: RetrievalStartEvent\n",
      "Tell me about LLMs?\n",
      "-----------------------\n",
      "-----------------------\n",
      "e984c840-919b-4dc7-943d-5c49fbff48b8\n",
      "2024-05-06 14:00:36.306265\n",
      "BaseEmbedding.get_query_embedding-d30934f4-7bd2-4425-beda-12b5f55bc38b\n",
      "Event type: EmbeddingStartEvent\n",
      "{'model_name': 'text-embedding-ada-002', 'embed_batch_size': 100, 'num_workers': None, 'additional_kwargs': {}, 'api_base': 'https://api.openai.com/v1', 'api_version': '', 'max_retries': 10, 'timeout': 60.0, 'default_headers': None, 'reuse_client': True, 'dimensions': None, 'class_name': 'OpenAIEmbedding'}\n",
      "-----------------------\n",
      "-----------------------\n",
      "c09fa993-a892-4efe-9f1b-7238ff6e5c62\n",
      "2024-05-06 14:00:36.481459\n",
      "BaseEmbedding.get_query_embedding-d30934f4-7bd2-4425-beda-12b5f55bc38b\n",
      "Event type: EmbeddingEndEvent\n",
      "['Tell me about LLMs?']\n",
      "[0.00793155562132597, 0.011421983130276203, -0.010342259891331196, -0.03294854983687401, -0.03647972270846367]\n",
      "-----------------------\n",
      "-----------------------\n",
      "b076d239-628d-4b4c-94ed-25aa2ca4b02b\n",
      "2024-05-06 14:00:36.484080\n",
      "BaseRetriever.retrieve-4e25a2a3-43a9-45e3-a7b9-59f4d54e8f00\n",
      "Event type: RetrievalEndEvent\n",
      "Tell me about LLMs?\n",
      "[NodeWithScore(node=TextNode(id_='8de2b6b2-3fda-4f9b-95a8-a3ced6cfb0e5', embedding=None, metadata={'filename': 'README.md', 'category': 'codebase'}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='29e2bc8f-b62c-4752-b5eb-11346c5cbe50', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'filename': 'README.md', 'category': 'codebase'}, hash='3183371414f6a23e9a61e11b45ec45f808b148f9973166cfed62226e3505eb05')}, text='Context\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.', start_char_idx=1, end_char_idx=1279, text_template='{metadata_str}\\n\\n{content}', metadata_template='{key}: {value}', metadata_seperator='\\n'), score=0.807312731672428)]\n",
      "-----------------------\n",
      "-----------------------\n",
      "5e3289be-c597-48e7-ad3f-787722b766ea\n",
      "2024-05-06 14:00:36.484436\n",
      "BaseSynthesizer.synthesize-23d8d12d-a36e-423b-8776-042f1ff62546\n",
      "Event type: SynthesizeStartEvent\n",
      "Tell me about LLMs?\n",
      "-----------------------\n",
      "-----------------------\n",
      "e9d9fe28-16d5-4301-8510-61aa11fa4951\n",
      "2024-05-06 14:00:36.486070\n",
      "Refine.get_response-e085393a-5510-4c3a-ba35-535caf58e159\n",
      "Event type: GetResponseStartEvent\n",
      "Tell me about LLMs?\n",
      "-----------------------\n",
      "-----------------------\n",
      "29ce3778-d7cc-4095-b6b7-c811cd61ca5d\n",
      "2024-05-06 14:00:36.486837\n",
      "LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0\n",
      "Event type: LLMPredictStartEvent\n",
      "metadata={'prompt_type': <PromptType.QUESTION_ANSWER: 'text_qa'>} template_vars=['context_str', 'query_str'] kwargs={'query_str': 'Tell me about LLMs?'} output_parser=None template_var_mappings={} function_mappings={} default_template=PromptTemplate(metadata={'prompt_type': <PromptType.QUESTION_ANSWER: 'text_qa'>}, template_vars=['context_str', 'query_str'], kwargs={'query_str': 'Tell me about LLMs?'}, output_parser=None, template_var_mappings=None, function_mappings=None, template='Context information is below.\\n---------------------\\n{context_str}\\n---------------------\\nGiven the context information and not prior knowledge, answer the query.\\nQuery: {query_str}\\nAnswer: ') conditionals=[(<function is_chat_model at 0x13a72af80>, ChatPromptTemplate(metadata={'prompt_type': <PromptType.CUSTOM: 'custom'>}, template_vars=['context_str', 'query_str'], kwargs={'query_str': 'Tell me about LLMs?'}, output_parser=None, template_var_mappings=None, function_mappings=None, message_templates=[ChatMessage(role=<MessageRole.SYSTEM: 'system'>, content=\"You are an expert Q&A system that is trusted around the world.\\nAlways answer the query using the provided context information, and not prior knowledge.\\nSome rules to follow:\\n1. Never directly reference the given context in your answer.\\n2. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines.\", additional_kwargs={}), ChatMessage(role=<MessageRole.USER: 'user'>, content='Context information is below.\\n---------------------\\n{context_str}\\n---------------------\\nGiven the context information and not prior knowledge, answer the query.\\nQuery: {query_str}\\nAnswer: ', additional_kwargs={})]))]\n",
      "{'context_str': 'filename: README.md\\ncategory: codebase\\n\\nContext\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.'}\n",
      "-----------------------\n",
      "-----------------------\n",
      "2042b4ab-99b4-410d-a997-ed97dda7a7d1\n",
      "2024-05-06 14:00:36.487359\n",
      "LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0\n",
      "Event type: LLMChatStartEvent\n",
      "[ChatMessage(role=<MessageRole.SYSTEM: 'system'>, content=\"You are an expert Q&A system that is trusted around the world.\\nAlways answer the query using the provided context information, and not prior knowledge.\\nSome rules to follow:\\n1. Never directly reference the given context in your answer.\\n2. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines.\", additional_kwargs={}), ChatMessage(role=<MessageRole.USER: 'user'>, content='Context information is below.\\n---------------------\\nfilename: README.md\\ncategory: codebase\\n\\nContext\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.\\n---------------------\\nGiven the context information and not prior knowledge, answer the query.\\nQuery: Tell me about LLMs?\\nAnswer: ', additional_kwargs={})]\n",
      "{}\n",
      "{'system_prompt': None, 'pydantic_program_mode': <PydanticProgramMode.DEFAULT: 'default'>, 'model': 'gpt-3.5-turbo', 'temperature': 0.1, 'max_tokens': None, 'logprobs': None, 'top_logprobs': 0, 'additional_kwargs': {}, 'max_retries': 3, 'timeout': 60.0, 'default_headers': None, 'reuse_client': True, 'api_base': 'https://api.openai.com/v1', 'api_version': '', 'class_name': 'openai_llm'}\n",
      "-----------------------\n",
      "-----------------------\n",
      "67b5c0f5-135e-4571-86a4-6e7efa6a40ff\n",
      "2024-05-06 14:00:37.627923\n",
      "LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0\n",
      "Event type: LLMChatEndEvent\n",
      "[ChatMessage(role=<MessageRole.SYSTEM: 'system'>, content=\"You are an expert Q&A system that is trusted around the world.\\nAlways answer the query using the provided context information, and not prior knowledge.\\nSome rules to follow:\\n1. Never directly reference the given context in your answer.\\n2. Avoid statements like 'Based on the context, ...' or 'The context information ...' or anything along those lines.\", additional_kwargs={}), ChatMessage(role=<MessageRole.USER: 'user'>, content='Context information is below.\\n---------------------\\nfilename: README.md\\ncategory: codebase\\n\\nContext\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.\\n---------------------\\nGiven the context information and not prior knowledge, answer the query.\\nQuery: Tell me about LLMs?\\nAnswer: ', additional_kwargs={})]\n",
      "assistant: LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
      "-----------------------\n",
      "-----------------------\n",
      "42cb1fc6-3d8a-4dce-81f1-de43617a37fd\n",
      "2024-05-06 14:00:37.628432\n",
      "LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0\n",
      "Event type: LLMPredictEndEvent\n",
      "LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
      "-----------------------\n",
      "-----------------------\n",
      "4498248d-d07a-4460-87c7-3a6f310c4cb3\n",
      "2024-05-06 14:00:37.628634\n",
      "Refine.get_response-e085393a-5510-4c3a-ba35-535caf58e159\n",
      "Event type: GetResponseEndEvent\n",
      "LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
      "-----------------------\n",
      "-----------------------\n",
      "f1d7fda7-de82-4149-8cd9-b9a17dba169b\n",
      "2024-05-06 14:00:37.628826\n",
      "BaseSynthesizer.synthesize-23d8d12d-a36e-423b-8776-042f1ff62546\n",
      "Event type: SynthesizeEndEvent\n",
      "LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
      "Tell me about LLMs?\n",
      "-----------------------\n",
      "-----------------------\n",
      "2f564649-dbbb-4adc-a552-552f54358112\n",
      "2024-05-06 14:00:37.629251\n",
      "BaseQueryEngine.query-a766ae6c-6445-43b4-b1fc-9c29bae99556\n",
      "Event type: QueryEndEvent\n",
      "LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.\n",
      "Tell me about LLMs?\n",
      "-----------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Response(response='LLMs are a type of technology used for knowledge generation and reasoning. They are pre-trained on large amounts of publicly available data.', source_nodes=[NodeWithScore(node=TextNode(id_='8de2b6b2-3fda-4f9b-95a8-a3ced6cfb0e5', embedding=None, metadata={'filename': 'README.md', 'category': 'codebase'}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='29e2bc8f-b62c-4752-b5eb-11346c5cbe50', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'filename': 'README.md', 'category': 'codebase'}, hash='3183371414f6a23e9a61e11b45ec45f808b148f9973166cfed62226e3505eb05')}, text='Context\\nLLMs are a phenomenal piece of technology for knowledge generation and reasoning.\\nThey are pre-trained on large amounts of publicly available data.\\nHow do we best augment LLMs with our own private data?\\nWe need a comprehensive toolkit to help perform this data augmentation for LLMs.\\n\\nProposed Solution\\nThat\\'s where LlamaIndex comes in. LlamaIndex is a \"data framework\" to help\\nyou build LLM  apps. It provides the following tools:\\n\\nOffers data connectors to ingest your existing data sources and data formats\\n(APIs, PDFs, docs, SQL, etc.)\\nProvides ways to structure your data (indices, graphs) so that this data can be\\neasily used with LLMs.\\nProvides an advanced retrieval/query interface over your data:\\nFeed in any LLM input prompt, get back retrieved context and knowledge-augmented output.\\nAllows easy integrations with your outer application framework\\n(e.g. with LangChain, Flask, Docker, ChatGPT, anything else).\\nLlamaIndex provides tools for both beginner users and advanced users.\\nOur high-level API allows beginner users to use LlamaIndex to ingest and\\nquery their data in 5 lines of code. Our lower-level APIs allow advanced users to\\ncustomize and extend any module (data connectors, indices, retrievers, query engines,\\nreranking modules), to fit their needs.', start_char_idx=1, end_char_idx=1279, text_template='{metadata_str}\\n\\n{content}', metadata_template='{key}: {value}', metadata_seperator='\\n'), score=0.807312731672428)], metadata={'8de2b6b2-3fda-4f9b-95a8-a3ced6cfb0e5': {'filename': 'README.md', 'category': 'codebase'}})"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from llama_index.core import Document, VectorStoreIndex\n",
    "\n",
    "index = VectorStoreIndex.from_documents([Document.example()])\n",
    "\n",
    "query_engine = index.as_query_engine()\n",
    "\n",
    "query_engine.query(\"Tell me about LLMs?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "85cc6751-b6ab-4c10-ae52-3814268a998d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BaseEmbedding.get_text_embedding_batch-632972aa-3345-49cb-ae2f-46f3166e3afc (SPAN)\n",
      "├── EmbeddingStartEvent: 7182e98f-1b8a-4aba-af18-3982b862c794\n",
      "└── EmbeddingEndEvent: ba86e41f-cadf-4f1f-8908-8ee90404d668\n",
      "\n",
      "\n",
      "BaseQueryEngine.query-a766ae6c-6445-43b4-b1fc-9c29bae99556 (SPAN)\n",
      "├── QueryStartEvent: 06935377-f1e4-4fb9-b866-86f7520dfe2b\n",
      "└── QueryEndEvent: 2f564649-dbbb-4adc-a552-552f54358112\n",
      "\n",
      "\n",
      "BaseRetriever.retrieve-4e25a2a3-43a9-45e3-a7b9-59f4d54e8f00 (SPAN)\n",
      "├── RetrievalStartEvent: 62608f4f-67a1-4e2c-a653-24a4430529bb\n",
      "└── RetrievalEndEvent: b076d239-628d-4b4c-94ed-25aa2ca4b02b\n",
      "\n",
      "\n",
      "BaseEmbedding.get_query_embedding-d30934f4-7bd2-4425-beda-12b5f55bc38b (SPAN)\n",
      "├── EmbeddingStartEvent: e984c840-919b-4dc7-943d-5c49fbff48b8\n",
      "└── EmbeddingEndEvent: c09fa993-a892-4efe-9f1b-7238ff6e5c62\n",
      "\n",
      "\n",
      "BaseSynthesizer.synthesize-23d8d12d-a36e-423b-8776-042f1ff62546 (SPAN)\n",
      "├── SynthesizeStartEvent: 5e3289be-c597-48e7-ad3f-787722b766ea\n",
      "└── SynthesizeEndEvent: f1d7fda7-de82-4149-8cd9-b9a17dba169b\n",
      "\n",
      "\n",
      "Refine.get_response-e085393a-5510-4c3a-ba35-535caf58e159 (SPAN)\n",
      "├── GetResponseStartEvent: e9d9fe28-16d5-4301-8510-61aa11fa4951\n",
      "└── GetResponseEndEvent: 4498248d-d07a-4460-87c7-3a6f310c4cb3\n",
      "\n",
      "\n",
      "LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0 (SPAN)\n",
      "├── LLMPredictStartEvent: 29ce3778-d7cc-4095-b6b7-c811cd61ca5d\n",
      "├── LLMChatStartEvent: 2042b4ab-99b4-410d-a997-ed97dda7a7d1\n",
      "├── LLMChatEndEvent: 67b5c0f5-135e-4571-86a4-6e7efa6a40ff\n",
      "└── LLMPredictEndEvent: 42cb1fc6-3d8a-4dce-81f1-de43617a37fd\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "event_handler.print_event_span_trees()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5f36f901",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BaseEmbedding.get_text_embedding_batch-632972aa-3345-49cb-ae2f-46f3166e3afc (0.326418)\n",
      "\n",
      "\n",
      "BaseQueryEngine.query-a766ae6c-6445-43b4-b1fc-9c29bae99556 (1.323617)\n",
      "└── RetrieverQueryEngine._query-40135aed-9aa5-4197-a05d-d461afb524d0 (1.32328)\n",
      "    ├── BaseRetriever.retrieve-4e25a2a3-43a9-45e3-a7b9-59f4d54e8f00 (0.178294)\n",
      "    │   └── VectorIndexRetriever._retrieve-8ead50e0-7243-42d1-b1ed-d2a2f2ceea48 (0.177893)\n",
      "    │       └── BaseEmbedding.get_query_embedding-d30934f4-7bd2-4425-beda-12b5f55bc38b (0.176907)\n",
      "    └── BaseSynthesizer.synthesize-23d8d12d-a36e-423b-8776-042f1ff62546 (1.144761)\n",
      "        └── CompactAndRefine.get_response-ec49a727-bf17-4d80-bf82-80ec2a906063 (1.144148)\n",
      "            └── Refine.get_response-e085393a-5510-4c3a-ba35-535caf58e159 (1.142698)\n",
      "                └── LLM.predict-007a74e7-34ff-488b-81b1-4ffb69df68a0 (1.141744)\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "simple_span_handler.print_trace_trees()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
